
#!coding:utf-8
# vim: tabstop=4 shiftwidth=4 softtabstop=4
import os
from rest_framework import status
from rest_framework.response import Response
from cvirt.cnode.storage import api

from cvirt.common import config,translate as _
from cvirt.manager.models import Storage,Server,Instance, VDisk, Cluster
from cvirt.manager.views import BaseListAPIView,BaseRetriveAPIView, NonModelBaseAPIView, NamedAPIViewMixIn
from cvirt.manager.serializers import StorageSerializer
from cvirt.tasks.storage import attach, detach, list_isos
from django.db import transaction

conf = config.load_settings()

class StorageListView(NamedAPIViewMixIn,BaseListAPIView):

    model = Storage
    serializer_class = StorageSerializer

    @transaction.commit_on_success
    def create(self, request, *args, **kwargs):
        cluster = self.get_params('cluster')
        name = self.get_params('name')
        type = self.get_params('type')
        protocol = self.get_params('protocol')

        if not name:
            return Response(_("名称不能为空"),status=status.HTTP_400_BAD_REQUEST)
        if not type:
            return Response(_("类型不能为空"),status=status.HTTP_400_BAD_REQUEST)
        if type == 'data':
            if protocol not in ['nfs','iscsi','local']:
                return Response(_("存储协议类型不合法"),status=status.HTTP_400_BAD_REQUEST)
        if type == 'iso':
            if protocol not in ['nfs','cifs']:
                return Response(_("存储协议类型不合法"),status=status.HTTP_400_BAD_REQUEST)

        host = self.get_params('host')
        path = self.get_params('path')
        if protocol == 'cifs':
            if not path:
                return Response(_("[CIFS]存储路径不能为空"),status=status.HTTP_400_BAD_REQUEST)
        if protocol == 'nfs':
            if not host or not path:
                return Response(_("[NFS]主机和存储路径不能为空"),status=status.HTTP_400_BAD_REQUEST)

        username = self.get_params('username')
        password = self.get_params('password')
        target = self.get_params('target')
        mount_point = os.path.join(conf.get('cnode.default_mount_point'), name)
        used = 0
        totalsize = 0

        if protocol == 'iscsi':
            if not host or not target:
                return Response(_("[ISCSI]主机和存储目标不能为空"),status=status.HTTP_400_BAD_REQUEST)
            target = target['target']

        storage = Storage.objects.first(type=type,protocol=protocol,host=host,
                                        path=path,target=target,cluster_id=cluster['id'])
        if storage: return Response(_("存储已存在"),status.HTTP_400_BAD_REQUEST)

        storage = Storage.objects.create(name=name,type=type,protocol=protocol,host=host,username=username,password=password,
                                         path=path,target=target,mount_point=mount_point,cluster_id=cluster['id'],
                                         status="pending", used=used, totalsize=totalsize)
        activity = attach.cluster_call(cluster['id'], storage)
        data = self.get_serializer(storage).data
        data.update(dict(activity=activity.id))
        return Response(data)

    def _get(self,request,*args,**kwargs):
        storages = Storage.objects.filter(type='data',status='running').order_by('-id')
        s = self.serializer_class(storages)
        return Response(s.data)

    @transaction.autocommit
    def isos(self,request,*args,**kwargs):
        cluster = Cluster.objects.get_or_none(pk=self.get_query_string('cluster_id'))
        if cluster:
            storages = Storage.objects.filter(type='iso',cluster=cluster,status='running')
            result = list_isos.call_in_cluster(cluster.id,storages)
            isos = result[1] if result else []
            return Response(isos)
        return Response({})

    def targets(self, request, *args, **kwargs):
        try:
            host = self.get_params('host')

            cmd ='iscsiadm -m discovery -t st -p %s|grep %s'%(host, host)
            out = os.popen(cmd).read().strip()
            targets = out.split('\n')
            iqns = []
            for target in targets:
                iqn = target.split()[-1]
                storage = Storage.objects.first(type='data',protocol='iscsi',host=host,
                                                target=target)
                if storage:continue
                iqns.append({'target': iqn})

            return Response({'data': iqns})
        except:
            return Response(_('无法连接主机'), status.HTTP_400_BAD_REQUEST)

    def luns(self, request, *args, **kwargs):
        current_path = os.path.dirname(os.path.abspath(__file__))
        try:
            target = self.get_params('target')
            host = self.get_params('host')
            username = self.get_params('username') if self.get_params('username') else ''
            password = self.get_params('password') if self.get_params('password') else ''
            #TODO luns.sh need move to specic dir(shankangjie)
            cmd = '%s/luns.sh %s %s %s %s' % (current_path, target, host, username, password)
            out = os.popen(cmd).read().strip()
            luns = out.split()
            result = []
            for lun in luns:
                _number,_mount,_size,_path = lun.split("|")
                disk_size = int(float(_size.replace('GB','')))
                vdisk = VDisk.objects.first(iscsilun__target=target,iscsilun__path=_path)
                if vdisk:
                    if not vdisk.instance:
                        #only display vdisk which not bind instance
                        result.append({'id':vdisk.id,'lunid':vdisk.name,'mountpoint':'','size':disk_size,
                                       'path':vdisk.iscsilun.path,'type':'虚拟磁盘','display':'%s|%s'%(vdisk.name,_size)})
                else:
                    result.append({'id':'','lunid':_number,'mountpoint':_mount,'size':disk_size,'path':_path,'type':'lun','display':'%s|%s'%(_number,_size)})

            return Response({'data': result})
        except:
            return Response(_('无法连接主机'), status.HTTP_400_BAD_REQUEST)


class StorageDetailView(NamedAPIViewMixIn,BaseRetriveAPIView):
    model = Storage
    serializer_class = StorageSerializer

    def relate_iso(self,storage):
        for inst in Instance.objects.filter(host__cluster = storage.cluster):
            for disk in inst.vdisk_set.exclude(device_type='disk'):
                #TODO 是否需要判断inst.status == 'running'?
                if disk.isopath and os.path.dirname(disk.isopath) == storage.mount_point:
                    return True


    @transaction.commit_on_success
    def delete(self, request, *args, **kwargs):
        # ask all host stop mount
        storage = Storage.objects.get_or_none(pk=self.pk)

        if storage:
            # if storage.status not in ['running','failed']:
            #     return Response(_("存储正在创建中，请等待操作完成后再删除"), status.HTTP_400_BAD_REQUEST)

            if storage.vdisk_set.count() == 0 and storage.template_set.count()==0 and \
                            storage.backuppolicy_set.count() == 0 and \
                    not self.relate_iso(storage):

                activity = detach.cluster_call(storage.cluster.id,storage)
                # activity = detach.apply_async(queue='simbas-pc',args=(storage,))
                return Response(dict(activity=activity.id))
            else:
                return Response(_("存储有关联的实体(磁盘，模板，iso)，不允许删除"),status.HTTP_400_BAD_REQUEST)

    def status(self,request,*args,**kwargs):

        storage  = Storage.objects.first(pk=self.pk)
        s = {}
        if storage:
            s['size'] = storage.totalsize
            s['used'] = storage.used
            s['image_length'] = storage.template_set.count()
            s['vdisk_length'] = storage.vdisk_set.count()
            s['inst_length'] = len(set([d.instance.id for d in VDisk.objects.filter(storage_id=self.pk) if d.instance]))
        return Response(s)


